/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package YottaTron.Sprites;

import YottaTron.*;
import YottaTron.Actions.AccelerateAction;
import YottaTron.Actions.Action;
import YottaTron.Equipment.Engine.Engine;
import YottaTron.Equipment.Gear.Gear;
import YottaTron.Equipment.Torso.Torso;
import YottaTron.Equipment.Weapons.*;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Iterator;
import org.lwjgl.util.Timer;

/**
 *
 * @author Cenda
 */
public class PlayerSprite extends Sprite {

    Runner runner;
    public ArrayList<Weapon> weapons;
    public Engine engine;
    public Gear gear;
    public Torso torso;
    private boolean key_left = false;
    public boolean key_left_last = false;
    private boolean key_right = false;
    public boolean key_right_last = false;
    private boolean key_up = false;
    public boolean key_up_last = false;
    private boolean key_down = false;
    public boolean key_down_last = false;
    private boolean mouseLeftPressed = false;
    public boolean mouseLeftPressed_last = false;
    private boolean mouseRightPressed = false;
    public boolean mouseRightPressed_last = false;
    private boolean kolize = false;
    public boolean shooting;
    public int aimX,  aimY;
    public double synchroX,synchroY;
    public short netAimAngle;
    double aimAngle;
    public boolean burning;
    public boolean controllable;
    public boolean dead;
    public int deaths,  frags,  rank;
    public int attackerID;
    public String nick;
    private ArrayList<Action> lastActions;
    public double serverX, serverY,serverDirection,serverSpeed;
    public float currentTime;
    public float synchroTime;

    //pouziva se k casova synchronizaci hrace mezi klientem a serverem
    

    public PlayerSprite(double x, double y, int width, int height, int ID, Runner runner) {
        super(x, y, width, height, ID);
        this.runner = runner;
        weapons = new ArrayList<Weapon>();
        lastActions = new ArrayList<Action>();
        setDirection(0);
        setSpeed(0);
        burning = false;
        controllable = false;//hrac je implicitne neovladatelny(protivnici)
        deaths = 0;
        frags = 0;
        rank = 1;
    }

    public void addLastAction(Action action){
        lastActions.add(action);
        if (lastActions.size() > 10) lastActions.remove(0);
    }

    public void addWeapon(Weapon weapon) {
        weapons.add(weapon);
    }

    public void addGear(Gear gear) {
        this.gear = gear;
    }

    public void addEngine(Engine engine) {
        this.engine = engine;
    }

    public void addTorso(Torso torso) {
        this.torso = torso;
        collisionDamage = torso.collisionDamage;
    }

    @Override
    public void handleCollision(Sprite target) {
        kolize = true;
        //pokud hraci oba narazi do sebe
        if (target != null) {
            target.damage(Math.abs((int) (target.getSpeed() * collisionDamage)) + Math.abs((int) (getSpeed() * target.collisionDamage)));
            this.damage(Math.abs((int) (getSpeed() * collisionDamage)) + Math.abs((int) (target.getSpeed() * collisionDamage)));
        }


        checkHitPoints();
        setSpeed(0);
    }

    public int getHitPoints() {
        return torso.hitPoints;
    }

   

    public void checkHitPoints() {
        if (torso.hitPoints < torso.maxHitPoints * 0.2 && !burning) {
            burning = true;
        }
        if (torso.hitPoints < 0) {
            die();
        }
    }

    public void setHitPoints(int hitPoints) {
        torso.hitPoints = hitPoints;
    }

    public void setKey_down(boolean key_down) {
        this.key_down = key_down;
    }

    public void setKey_left(boolean key_left) {
        this.key_left = key_left;
    }

    public void setKey_right(boolean key_right) {
        this.key_right = key_right;
    }

    public void setKey_up(boolean key_up) {
        this.key_up = key_up;
    }

    public boolean isKey_down() {
        return key_down;
    }

    public boolean isKey_left() {
        return key_left;
    }

    public boolean isKey_right() {
        return key_right;
    }

    public boolean isKey_up() {
        return key_up;
    }

    @Override
    public void damage(int damage) {
        torso.hitPoints = torso.hitPoints - damage;
        checkHitPoints();
    }

    public void damage(int damage, Sprite attacker) {
        torso.hitPoints = torso.hitPoints - damage;
        attackerID = attacker.ID;
        checkHitPoints();
    }

    public boolean isMouseLeftPressed() {
        return mouseLeftPressed;
    }

    public void setMouseLeftPressed(boolean mouseLeftPressed) {
        this.mouseLeftPressed = mouseLeftPressed;
    }

    public boolean isMouseRightPressed() {
        return mouseRightPressed;
    }

    public void setMouseRightPressed(boolean mouseRightPressed) {
        this.mouseRightPressed = mouseRightPressed;
    }

    public void setAimAngle() {
        aimAngle = -Math.atan2(getCenterX() - aimX, getCenterY() - aimY);

        if (aimAngle < 0) {
            aimAngle = aimAngle + Math.PI * 2;
        }
        if (aimAngle > Math.PI * 2) {
            aimAngle = aimAngle - Math.PI * 2;
        }

    }

    public void setAimAngle(double aim) {
        aimAngle = aim;
//        aimX = Math.tan(aim);
//        aimY = Math.tan(aim);

        if (aimAngle < 0) {
            aimAngle = aimAngle + Math.PI * 2;
        }
        if (aimAngle > Math.PI * 2) {
            aimAngle = aimAngle - Math.PI * 2;
        }

    }

    public double getAimAngle() {
        return aimAngle;
    }

    public ArrayList<Weapon> getWeapons() {
        return weapons;
    }

    public void die(){
    dead = true;
    deaths++;
    //pridame skoliteli frag
    if(attackerID>=1000&&attackerID<10000){
        ((PlayerSprite)runner.getSpriteByID(attackerID)).frags++;
    }
    computeRank();
    runner.ShowAnimationAt(new ImagesPlayer(runner.animationGraphics[1], 1d, 1, runner.globalTickTime, false, runner), (int) getX(), (int) getY());
    }

    @Override
    public void destroySprite(Runner runner) {
        active = false;
        runner.removePlayer(this);
        runner.dePopulate(this);
           }
    //spocita poradi robota v zebricku areny - rank 1 = nejlepsi
    public void computeRank() {
        rank = 1;
        //pokud ma nejaky hrac vic fragu, je automaticky lepsi
        for (int i = 0; i < runner.players.size(); i++) {
            if (runner.players.get(i).frags > frags) {
                rank++;
            }
            //pokud ma stejne fragu jako my, ale ma mensi pocet smrti, je lepsi
            if (runner.players.get(i).frags == frags) {
                if (runner.players.get(i).deaths > deaths) {
                    rank++;
                }
            }

        }
    }

   

    public double getMaxSpeed() {
        return engine.maxSpeed;
    }

    @Override
    public double getAcceleration() {
        return engine.acceleration;
    }

    @Override
    public double getBrakePower(){
    return gear.brakePower;
    }

    @Override
    public double getTurnSpeed(){
    return gear.turningSpeed;
    }

   

    @Override
    public ArrayList<Point2D> getShape() {
        return torso.graphics.getShape();
    }

    //zjisti na kterych polickach herniPole se sprite nachazi
    @Override
    public ArrayList<Point2D> getOccupiedCells() {
        ArrayList<Point2D> occupiedCells = new ArrayList<Point2D>();
        for (Iterator<Point2D> it = torso.graphics.getShape().iterator(); it.hasNext();) {
            Point2D point = it.next();
            occupiedCells.add(new Point(runner.XToTiles((int) (point.getX() + getX())), runner.YToTiles((int) (point.getY() + getY()))));
        }
        return occupiedCells;
    }

    /* vrati pole o deseti prvcich, ktere obsahuje typy zbrani umistene na hracovi
     * je to kvuli posilani newPlayer()
     */
    public byte[] weaponsToArray() {
        byte[] ret = new byte[10];
        for (int i = 0; i < ret.length; i++) {
            if (i < weapons.size()) {
                ret[i] = weapons.get(i).type;
                System.out.println("PlayerSprite weaponsToArray type " + ret[i]);
            } else {
                ret[i] = 0;
            }
        }
        System.out.println("   ");

        return ret;
    }

    /* prida zbrane jejichz typy jsou ve vstupnim poli
     * 0 znaci zadnou zbran
     */
    public void addWeapons(byte[] weapons, GraphicsLoader[] spriteGraphics, ImagesPlayer[] animations, AnimatedGraphicsLoader[] animationGraphics) {
        for (int i = 0; i < weapons.length; i++) {
            if (weapons[i] != 0) {
                switch (weapons[i]) {
                    case Weapon.MINIGUN:
                        this.addWeapon(new Minigun(
                                (RotatingGraphicsLoader) spriteGraphics[Runner.GSP_MINIGUN],
                                spriteGraphics[Runner.GSP_MINIGUN_PROJECTILE],
                                animations[Runner.A_MINIGUN_SHOOTING],
                                animationGraphics[Runner.GA_MINIGUN_PROJECTILE_HIT]));
                        break;

                    case Weapon.ROCKET_LAUNCHER:
                        this.addWeapon(new RocketLauncher(
                                (RotatingGraphicsLoader) spriteGraphics[Runner.GSP_ROCKET_LAUNCHER],
                                (RotatingGraphicsLoader) spriteGraphics[Runner.GSP_ROCKET_PROJECTILE],
                                animations[Runner.A_ROCKET_LAUNCHER_SHOOTING],
                                animationGraphics[Runner.GA_ROCKET_LAUNCHER_PROJECTILE_HIT]));
                        break;
                    case Weapon.DOUBLE_RL:
                        this.addWeapon(new DoubleRL(
                                (RotatingGraphicsLoader) spriteGraphics[Runner.GSP_DOUBLE_ROCKET_LAUNCHER],
                                (RotatingGraphicsLoader) spriteGraphics[Runner.GSP_ROCKET_PROJECTILE],
                                animations[Runner.A_ROCKET_LAUNCHER_SHOOTING],
                                animationGraphics[Runner.GA_ROCKET_LAUNCHER_PROJECTILE_HIT]));
                        break;

                }
            }
        }
    }
    //obnovi hrace po smrti
    public void respawn(){
    x = Math.random() * (runner.width - 100) + 50;
    y = Math.random() * (runner.height - 100) + 50;
    dead= false;
    torso.hitPoints = torso.maxHitPoints;
    
    }

    public void correctPosition(double x, double y, double direction, double speed){
    this.x = x;
    this.y = y;
    this.direction = direction;
    this.speed = speed;
    }

    


}
